# -*- coding: utf-8 -*-

"""
Module implementing CSerialScope.
"""
import time
import re
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

from Ui_SerialScope import Ui_Dialog

from DataManager import CDataManager
from DataManager import CSampleThread
from CPlotManager import CPlotManager
from CommSetting import CCommSetting
from About import CAbout

import serial
#import numpy as np

class CSerialScope(QDialog, Ui_Dialog):
    """
    Class documentation goes here.
    """
    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent reference to the parent widget
        @type QWidget
        """
        super(CSerialScope, self).__init__(parent)
        self.setupUi(self)
        
        self.started = False
        self.count = 0

        self.timerInterval = 50
        self.timer = QTimer()
        self.timer.timeout.connect(self.OnTimer)    
        
        self.rowName = 0
        self.rowAddr = 1
        self.rowSize = 2
        self.rowSign = 3
        self.rowScale = 4
        self.rowOffset = 5
        
        self.btnHold.setEnabled(False)
        self.btnHold.setChecked(False)
        self.device = serial.Serial(timeout = 0.1)        
        self.dataManager = CDataManager(self.device)
        self.plotManager = CPlotManager(self.dataManager, self)
        self.commSetting = CCommSetting()
        self.about = CAbout(parent = self)
        self.sampleThread = CSampleThread(self.dataManager)

        
        self.nameCbxs = [QComboBox(), QComboBox(), QComboBox(), QComboBox()]
        self.sizeCbxs = [QComboBox(), QComboBox(), QComboBox(), QComboBox()]
        self.signCbxs = [QComboBox(), QComboBox(), QComboBox(), QComboBox()]
        
        index = 0
        for combo in self.nameCbxs: 
            combo.setEditable(True)
            combo.addItem('')
            combo.setDuplicatesEnabled(False)
            cmp = combo.completer()
            cmp.setCompletionMode(QCompleter.PopupCompletion)
            cmp.setCaseSensitivity(Qt.CaseInsensitive)
            cmp.setFilterMode(Qt.MatchContains)   
            combo.setProperty('ch', index)
            index = index + 1
            
            combo.currentIndexChanged.connect(self.GetAddrFromName)
        
        for combo in self.sizeCbxs:
            combo.addItem('1')
            combo.addItem('8')
            combo.addItem('16')
            combo.addItem('32')
            combo.setCurrentIndex(2)
            
        for combo in self.signCbxs:
            combo.addItem('U')
            combo.addItem('S')
            
        for col in range(0, 4):
            self.tblChSetting.setCellWidget(self.rowName, col, self.nameCbxs[col])
            self.tblChSetting.setCellWidget(self.rowSize, col, self.sizeCbxs[col])            
            self.tblChSetting.setCellWidget(self.rowSign, col, self.signCbxs[col])  
            
        self.pgsDataBuf.setValue(0)
        
        
        self.pt = re.compile('^1 +[\dA-Fa-f]{8} +_\w+')
        self.ptAddr = re.compile('[\dA-Fa-f]{8}')
        self.ptName = re.compile('_\w+')
        self.ptMember = re.compile('_\w+__')
        self.ptClass = re.compile('__\d+\w+')
            
    @pyqtSlot()
    def on_btnCommSetting_clicked(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        self.commSetting.Show()
    
    @pyqtSlot()
    def on_btnLoadMap_clicked(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        
        file, filter = QFileDialog.getOpenFileName(
        self,
        'Select map file',
        '',
        "Map file(*.map)",
        None,
        QFileDialog.DontUseNativeDialog)
        
        
        if file != None and file != '':

            #self.statusBar.showMessage(file)             #在状态栏显示文件地址
            #Clear items first
            for combo in self.nameCbxs:
                combo.clear()
                combo.addItem('')
                        
            for line in open(file):
                
                match = self.pt.match(line)
                if match:
                    item = self.ParseMapRecord(line)
                    
                    # Add to combo
                    for combo in self.nameCbxs:
                        combo.addItem(item)
    
    
    def ParseMapRecord(self, record):
        
        match = self.ptAddr.search(record)
        addr = '0x' + match.group()
        
        match = self.ptName.search(record)
        name = match.group()
        
        match = self.ptClass.search(name)
        if match:
            
            cls = match.group()
            
            if cls[3] >= '0' and cls[3] <= '9':
                cls = cls[4:len(cls)]
            else:
                cls = cls[3:len(cls)]
           
            match = self.ptMember.search(name)
            member = match.group()
            member = member[1:len(member) - 2] 
            
            varName = member + '::' + cls
            
        else:
            varName = name[1:len(name)]
        
        return varName + ' ' + addr  

        
    
    @pyqtSlot()
    def on_btnStart_clicked(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        # raise NotImplementedError
        
        if self.started:
            self.sampleThread.stop()
            # Wait for the thread stop
            time.sleep(0.2)
            self.device.close()
            self.btnStart.setText('Start') 
            self.started = False 
            self.timer.stop()
            self.count = 0
            self.btnHold.setEnabled(False)
            self.btnHold.setChecked(False)
            self.plotManager.Finalize()
            
        else:
            
            text = 'Port = ' + self.commSetting.port + ' '
            text = text + 'Baud = ' + str(self.commSetting.baud) + '\n'
            self.label.setText(text)
            
            try:            
                
                self.GetChProperties()
                
                self.device.port = self.commSetting.port
                self.device.baudrate = self.commSetting.baud
                self.device.parity = self.commSetting.parity
                self.device.stopbits = self.commSetting.stopbit

                self.device.close()
                self.device.open()

                self.device.reset_input_buffer()
                self.device.reset_output_buffer()

                
                self.dataManager.ClearData()
                self.dataManager.StartSample()
                self.sampleThread.start()
                
                
                self.plotManager.ReInit()
                self.plotManager.Show()
                
                
                self.timer.start(self.timerInterval)
                self.btnStart.setText('Stop')   
                self.started = True
                self.btnHold.setEnabled(True)
                self.btnHold.setChecked(False)
                
            except Exception as e:
                
                QMessageBox.critical(self, 'Error', str(e),  QMessageBox.Yes)
                
                
        
    
    @pyqtSlot()
    def on_btnAbout_clicked(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        self.about.show()
    
    @pyqtSlot()
    def on_btnShow_clicked(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        self.plotManager.Show()

    def OnTimer(self): 
        
        #self.dataManager.GetData()
        
        if self.btnHold.isChecked() == False:
            self.plotManager.Update()
        
        self.count = self.count + 1
        self.label.setText(str(self.dataManager.dataList[0].length()))
        
        self.pgsDataBuf.setValue(self.dataManager.dataList[0].length() * 100 /len(self.dataManager.dataList[0].data))
        
    def GetChProperties(self):
        
        for col in range(0, 4):
            
            name = self.nameCbxs[col].currentText()
            if name == '':
                name = 'ch' + str(col + 1)
                
            addr = self.tblChSetting.item(self.rowAddr, col).text()
            if addr != '':
                if len(addr) > 2 and (addr[0:2] == '0x' or addr[0:2] == '0X'):
                    addr = int(addr, 16)
                else:
                    try:
                        addr = int(addr)
                    except:
                        addr = 0
                        
            else:
                addr = 0
                
            try:
                scale = self.tblChSetting.item(self.rowScale, col).text()
                scale = float(scale)
            except:
                scale = 1
            
            try:
                offset = self.tblChSetting.item(self.rowOffset, col).text()
                offset = float(offset)
            except:
                offset = 0
                        
                        
            size = self.sizeCbxs[col].currentText()
            sign = self.signCbxs[col].currentText()
            
            if col == 0 and addr == 0:
                raise Exception('Addr of ch1 cannot be 0!')
            
            self.dataManager.UpdateChProperties(col, name, addr, size, sign, scale, offset)
            
    
    def GetAddrFromName(self,  p0):
        
        
        # To skip current index changed event as the sender currently is the 'load map' button
        try:    
            #self.label.setText(str(p0))
            qsender = self.sender()
            ch = qsender.property('ch')
            name = qsender.currentText()   
            addr = name.split(' ')[1]
            newItem = QTableWidgetItem(addr)
            self.tblChSetting.setItem(self.rowAddr,  ch,  newItem)            
        except:
            None

    
    @pyqtSlot(bool)
    def on_btnHold_clicked(self, checked):
        """
        Slot documentation goes here.
        
        @param checked DESCRIPTION
        @type bool
        """
        # TODO: not implemented yet
        if checked == True:
            self.plotManager.Finalize()
